package wodegua.d29_多线程;

/**
 * 同步方法
 * 作用:把访问共享资源的核心方法给上锁，以此保证线程安全。
 * 修饰符 synchronized 返回值类型 方法名称(形参列表){操作共享资源的代码}
 * 原理:每次只能一个线程进入，执行完毕以后自动解锁，其他线程才可以进来执行，
 *
 * 同步方法底层原理
 * 1.同步方法其实底层也是有隐式锁对象的，只是锁的范围是整个方法代码
 * 2.如果方法是实例方法:同步方法默认用this作为的锁对象。
 * 3.如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
 *
 * 1、是同步代码块好还是同步方法好一点?
 * ●范围上:同步代码块锁的范围更小，同步方法锁的范围更大。
 * ●可读性:同步方法更好。
 */
public class d4_thread_safe_sync_method {
    public static void main(String[] args) {
        AccountSyncMethod account = new AccountSyncMethod("id-1101",100000);
        new DrawThreadSyncMethod(account, "小明").start();
        new DrawThreadSyncMethod(account, "小红").start();

        AccountSyncMethod account2 = new AccountSyncMethod("id-1102",100000);
        new DrawThreadSyncMethod(account2, "小黑").start();
        new DrawThreadSyncMethod(account2, "小白").start();
    }
}

class AccountSyncMethod{
    private String cardId;
    private double money;

    public AccountSyncMethod() {
    }

    public AccountSyncMethod(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    public synchronized void DrawMoney(double money){
        String name = Thread.currentThread().getName();
        if (this.money >= money) {
            System.out.println(name + "来取" + money);
            this.money -= money;
            System.out.println(name + "来取" + money + "后，余额="+this.money);
        } else {
            System.out.println(name + "来取钱余额不足");
        }
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

class DrawThreadSyncMethod extends Thread{
    private AccountSyncMethod account;
    public DrawThreadSyncMethod() {
    }

    public DrawThreadSyncMethod(AccountSyncMethod account, String name) {
        super(name);
        this.account = account;
    }

    @Override
    public void run() {
        account.DrawMoney(100000);
    }
}
